package com.apestech.api.workflow.lib.element;

import com.apestech.framework.json.JSON;
import com.apestech.framework.json.JSONArray;
import com.apestech.framework.json.JSONObject;
import com.apestech.framework.util.StringUtil;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.runtime.ProcessInstanceQuery;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;

import java.util.ArrayList;
import java.util.List;

/**
 * API原生对象方式查询条件，该功能仅针对查询报表使用，正常业务单据查询不推荐使用，查询效率低，慎用！
 *
 * @author hup
 * @create 2018-07-18-9:51
 */
public class FlowQueryCondition extends StringUtil {

    private TaskQuery taskQuery;
    private HistoricTaskInstanceQuery hisTaskQuery;
    private ProcessInstanceQuery proceQuery;
    private HistoricProcessInstanceQuery hisProcessQuery;
    private JSONObject param;
    private String type;

    public FlowQueryCondition(Object query, JSONObject param) {
        if(query instanceof TaskQuery){
            this.taskQuery= (TaskQuery) query;
        } else if(query instanceof  HistoricTaskInstanceQuery){
            this.hisTaskQuery= (HistoricTaskInstanceQuery) query;
        } else if(query instanceof  ProcessInstanceQuery){
            this.proceQuery= (ProcessInstanceQuery) query;
        } else if(query instanceof  HistoricProcessInstanceQuery){
            this.hisProcessQuery= (HistoricProcessInstanceQuery) query;
        }
        this.param=param;
    }

    public void getWhere() throws Exception {
        if(this.taskQuery!=null || this.hisTaskQuery!=null){
            this.getWhereTask(iniParam(param));
        } else if(this.proceQuery!=null || this.hisProcessQuery!=null){
            this.getWhereProc(iniParam(param));
        }
    }

    private JSONObject iniParam(JSONObject input) throws Exception {
        if(input==null){
            input=new JSONObject();
        }
        JSONObject param=new JSONObject();
        if(input.get("condition")==null){
            return input;
        }
        JSONArray list= JSON.toJSONArray(input.get("condition"));
        int len=input.size();
        ArrayList<String> klist=input.getKeylist();
        for(int i=0; i<len; i++){
            String key=klist.get(i);
            if(!key.equals("condition")){
                param.put(key, input.get(key));
            } else {
                int llen=list.size();
                for(int j=0; j<llen; j++){
                    JSONObject mx=list.getJSONObject(j);
                    String field=mx.getString("field");
                    param.put(field, mx);
                }
            }
        }
        return param;
    }

    private void getWhereTask(JSONObject param) throws Exception {
        ArrayList<String> klist=param.getKeylist();
        int len=klist.size();
        for(int i=0; i<len; i++){
            String key=klist.get(i);
            Object value=param.get(key);
            String operator=null;
            Object val=null;
            if(value instanceof JSONObject) {
                JSONObject m = (JSONObject) value;
                operator=m.getString("operator");
                val=m.get("value");
            } else {
                val=value;
            }
            switch (key){
                case "processInstanceId":{
                    if(operator!=null){
                        if("LIKE".equals(operator)){
                            if(taskQuery!=null){
                                taskQuery.processDefinitionKeyLike(castToString(val));
                            } else {
                                hisTaskQuery.processDefinitionKeyLike(castToString(val));
                            }
                            break;
                        } else if("IN".equals(operator)){
                            if(taskQuery!=null){
                                taskQuery.processDefinitionKeyIn((List<String>) val);
                            } else {
                                hisTaskQuery.processDefinitionKeyIn((List<String>) val);
                            }
                            break;
                        }
                    }
                    if(taskQuery!=null){
                        taskQuery.processInstanceId(castToString(val));
                    } else {
                        hisTaskQuery.processInstanceId(castToString(val));
                    }
                    break;
                }
                case "executionId":{
                    if(taskQuery!=null){
                        taskQuery.executionId(castToString(val));
                    } else {
                        hisTaskQuery.executionId(castToString(val));
                    }
                    break;
                }
                case "taskName":{
                    if(operator!=null){
                        if("LIKE".equals(operator)){
                            if(taskQuery!=null){
                                taskQuery.taskNameLike(castToString(val));
                            } else {
                                hisTaskQuery.taskNameLike(castToString(val));
                            }
                            break;
                        } else if("IN".equals(operator)) {
                            if(taskQuery!=null){
                                taskQuery.taskNameIn((List<String>) val);
                            } else {
                                hisTaskQuery.taskNameIn((List<String>) val);
                            }
                            break;
                        }
                    }
                    if(taskQuery!=null){
                        taskQuery.taskName(castToString(val));
                    } else {
                        hisTaskQuery.taskName(castToString(val));
                    }
                    break;
                }
                case "taskDescription":{
                    if(operator!=null){
                        if("LIKE".equals(operator)){
                            if(taskQuery!=null){
                                taskQuery.taskDescriptionLike(castToString(val));
                            } else {
                                hisTaskQuery.taskDescriptionLike(castToString(val));
                            }
                            break;
                        }
                    }
                    if(taskQuery!=null){
                        taskQuery.taskDescription(castToString(val));
                    } else {
                        hisTaskQuery.taskDescription(castToString(val));
                    }
                    break;
                }
                case "taskId":{
                    if(taskQuery!=null){
                        taskQuery.taskId(castToString(val));
                    } else {
                        hisTaskQuery.taskId(castToString(val));
                    }
                    break;
                }
                case "taskPriority":{
                    if(operator!=null){
                        if("MIN".equals(operator)){
                            if(taskQuery!=null){
                                taskQuery.taskMinPriority(castToInt(value));
                            } else {
                                hisTaskQuery.taskMinPriority(castToInt(value));
                            }
                            break;
                        } else if("MAX".equals(operator)) {
                            if(taskQuery!=null){
                                taskQuery.taskMaxPriority(castToInt(value));
                            } else {
                                hisTaskQuery.taskMaxPriority(castToInt(value));
                            }
                            break;
                        }
                    }
                    if(taskQuery!=null){
                        taskQuery.taskPriority(castToInt(value));
                    } else {
                        hisTaskQuery.taskPriority(castToInt(value));
                    }
                    break;
                }
                case "taskAssignee":{
                    if(operator!=null){
                        if("LIKE".equals(operator)){
                            if(taskQuery!=null){
                                taskQuery.taskAssigneeLike(castToString(val));
                            } else {
                                hisTaskQuery.taskAssigneeLike(castToString(val));
                            }
                            break;
                        }
                    }
                    if(taskQuery!=null){
                        taskQuery.taskAssignee(castToString(val));
                    } else {
                        hisTaskQuery.taskAssignee(castToString(val));
                    }
                    break;
                }
                case "taskOwner":{
                    if(operator!=null){
                        if("LIKE".equals(operator)){
                            if(taskQuery!=null){
                                taskQuery.taskOwnerLike(castToString(val));
                            } else {
                                hisTaskQuery.taskOwnerLike(castToString(val));
                            }
                            break;
                        }
                    }
                    if(taskQuery!=null){
                        taskQuery.taskOwner(castToString(val));
                    } else {
                        hisTaskQuery.taskOwner(castToString(val));
                    }
                    break;
                }
                case "taskTenantId":{
                    if(operator!=null){
                        if("LIKE".equals(operator)){
                            if(taskQuery!=null){
                                taskQuery.taskTenantIdLike(castToString(val));
                            } else {
                                hisTaskQuery.taskTenantIdLike(castToString(val));
                            }
                            break;
                        }
                    }
                    if(taskQuery!=null){
                        taskQuery.taskTenantId(castToString(val));
                    } else {
                        hisTaskQuery.taskTenantId(castToString(val));
                    }
                    break;
                }
                case "processInstanceBusinessKey":{
                    if("LIKE".equals(operator)){
                        if(taskQuery!=null){
                            taskQuery.processInstanceBusinessKeyLike(castToString(val));
                        } else {
                            hisTaskQuery.processInstanceBusinessKeyLike(castToString(val));
                        }
                        break;
                    }
                    if(taskQuery!=null){
                        taskQuery.processInstanceBusinessKey(castToString(val));
                    } else {
                        hisTaskQuery.processInstanceBusinessKey(castToString(val));
                    }
                    break;
                }
                case "taskCreated":{
                    if("LTE".equals(operator)){
                        if(taskQuery!=null){
                            taskQuery.taskCreatedBefore(castToDate(val));
                        } else {
                            hisTaskQuery.taskCreatedBefore(castToDate(val));
                        }
                        break;
                    } else if("GTE".equals(operator)){
                        if(taskQuery!=null){
                            taskQuery.taskCreatedAfter(castToDate(val));
                        } else {
                            hisTaskQuery.taskCreatedAfter(castToDate(val));
                        }
                        break;
                    }
                    if(taskQuery!=null){
                        taskQuery.taskCreatedOn(castToDate(val));
                    } else {
                        hisTaskQuery.taskCreatedOn(castToDate(val));
                    }
                    break;
                }
                case "taskDefinitionKey":{
                    if("LIKE".equals(operator)){
                        if(taskQuery!=null){
                            taskQuery.taskDefinitionKeyLike(castToString(val));
                        } else {
                            hisTaskQuery.taskDefinitionKeyLike(castToString(val));
                        }
                        break;
                    }
                    if(taskQuery!=null){
                        taskQuery.taskDefinitionKey(castToString(val));
                    } else {
                        hisTaskQuery.taskDefinitionKey(castToString(val));
                    }
                    break;
                }
                case "taskDueDate":{
                    if("LTE".equals(operator)){
                        if(taskQuery!=null){
                            taskQuery.taskDueBefore(castToDate(val));
                        } else {
                            hisTaskQuery.taskDueBefore(castToDate(val));
                        }
                        break;
                    } else if("GTE".equals(operator)){
                        if(taskQuery!=null){
                            taskQuery.taskDueAfter(castToDate(val));
                        } else {
                            hisTaskQuery.taskDueAfter(castToDate(val));
                        }
                        break;
                    }
                    if(taskQuery!=null){
                        taskQuery.taskDueDate(castToDate(val));
                    } else {
                        hisTaskQuery.taskDueDate(castToDate(val));
                    }
                    break;
                }
                case "processDefinitionName":{
                    if("LIKE".equals(operator)){
                        if(taskQuery!=null){
                            taskQuery.processDefinitionNameLike(castToString(val));
                        } else {
                            hisTaskQuery.processDefinitionNameLike(castToString(val));
                        }
                        break;
                    }
                    if(taskQuery!=null){
                        taskQuery.processDefinitionName(castToString(val));
                    } else {
                        hisTaskQuery.processDefinitionName(castToString(val));
                    }
                    break;
                }
                case "processCategory":{
                    if("IN".equals(operator)){
                        if(taskQuery!=null){
                            taskQuery.processCategoryIn((List<String>) val);
                        } else {
                            hisTaskQuery.processCategoryIn((List<String>) val);
                        }
                        break;
                    } else if("NIN".equals(operator)) {
                        if(taskQuery!=null){
                            taskQuery.processCategoryNotIn((List<String>) val);
                        } else {
                            hisTaskQuery.processCategoryNotIn((List<String>) val);
                        }
                        break;
                    }
                    break;
                }
                case "deploymentId":{
                    if("IN".equals(operator)){
                        if(taskQuery!=null){
                            taskQuery.deploymentIdIn((List<String>) val);
                        } else {
                            hisTaskQuery.deploymentIdIn((List<String>) val);
                        }
                        break;
                    }
                    if(taskQuery!=null){
                        taskQuery.deploymentId(castToString(val));
                    } else {
                        hisTaskQuery.deploymentId(castToString(val));
                    }
                    break;
                }
                default:{
                    setVarQuery(key, operator, val);
                    break;
                }
            }
        }
    }

    private void getWhereProc(JSONObject param) throws Exception {
        ArrayList<String> klist=param.getKeylist();
        int len=klist.size();
        for(int i=0; i<len; i++){
            String key=klist.get(i);
            Object value=param.get(key);
            String operator=null;
            Object val=null;
            if(value instanceof JSONObject) {
                JSONObject m = (JSONObject) value;
                operator=m.getString("operator");
                val=m.get("value");
            } else {
                val=value;
            }
            switch (key){
                case "processInstanceId":{
                    if(proceQuery!=null){
                        proceQuery.processInstanceId(castToString(val));
                    } else {
                        hisProcessQuery.processInstanceId(castToString(val));
                    }
                    break;
                }
                case "businessKey":{
                    if(proceQuery!=null){
                        proceQuery.processInstanceBusinessKey(castToString(val));
                    } else {
                        hisProcessQuery.processInstanceBusinessKey(castToString(val));
                    }
                    break;
                }
                case "tenantId":{
                    if(operator!=null){
                        if("LIKE".equals(operator)){
                            if(proceQuery!=null){
                                proceQuery.processInstanceTenantIdLike(castToString(value));
                            } else {
                                hisProcessQuery.processInstanceTenantIdLike(castToString(value));
                            }
                            break;
                        }
                    }
                    if(proceQuery!=null){
                        proceQuery.processInstanceTenantId(castToString(val));
                    } else {
                        hisProcessQuery.processInstanceTenantId(castToString(val));
                    }
                    break;
                }
                case "definitionCategory":{
                    if(proceQuery!=null){
                        proceQuery.processDefinitionCategory(castToString(val));
                    } else {
                        hisProcessQuery.processDefinitionCategory(castToString(val));
                    }
                    break;
                }
                case "definitionName":{
                    if(proceQuery!=null){
                        proceQuery.processDefinitionName(castToString(value));
                    } else {
                        hisProcessQuery.processDefinitionName(castToString(value));
                    }
                    break;
                }
                case "definitionKey":{
                    if(proceQuery!=null){
                        proceQuery.processDefinitionKey(castToString(value));
                    } else {
                        hisProcessQuery.processDefinitionKey(castToString(value));
                    }
                    break;
                }
                case "definitionId":{
                    if(proceQuery!=null){
                        proceQuery.processDefinitionId(castToString(value));
                    } else {
                        hisProcessQuery.processDefinitionId(castToString(value));
                    }
                    break;
                }
                case "superProcessInstanceId":{
                    if(proceQuery!=null){
                        proceQuery.superProcessInstanceId(castToString(value));
                    } else {
                        hisProcessQuery.superProcessInstanceId(castToString(value));
                    }
                    break;
                }
                case "involvedUser":{
                    if(proceQuery!=null){
                        proceQuery.involvedUser(castToString(value));
                    } else {
                        hisProcessQuery.involvedUser(castToString(value));
                    }
                    break;
                }
                default:{
                    setVarQuery(key, operator, val);
                    break;
                }
            }
        }
    }

    private void setVarQuery(String key, String operator, Object value){
        if(operator==null) operator="";
        switch(operator){
            case "LIKE":{
                if(taskQuery!=null){
                    taskQuery.processVariableValueLike(key, (String) value);
                } else if(hisTaskQuery!=null){
                    hisTaskQuery.processVariableValueLike(key, (String) value);
                } else if(proceQuery!=null){
                    proceQuery.variableValueLike(key, (String) value);
                } else {
                    hisProcessQuery.variableValueLike(key, (String) value);
                }
                break;
            }
            case "NE":{
                if(taskQuery!=null){
                    taskQuery.processVariableValueNotEquals(key, value);
                } else if(hisTaskQuery!=null){
                    hisTaskQuery.processVariableValueNotEquals(key, value);
                } else if(proceQuery!=null){
                    proceQuery.variableValueNotEquals(key, value);
                } else {
                    hisProcessQuery.variableValueNotEquals(key, value);
                }
                break;
            }
            case "GT":{
                if(taskQuery!=null){
                    taskQuery.processVariableValueGreaterThan(key, value);
                } else if(hisTaskQuery!=null){
                    hisTaskQuery.processVariableValueGreaterThan(key, value);
                } else if(proceQuery!=null){
                    proceQuery.variableValueGreaterThan(key, value);
                } else {
                    hisProcessQuery.variableValueGreaterThan(key, value);
                }
                break;
            }
            case "GTE":{
                if(taskQuery!=null){
                    taskQuery.processVariableValueGreaterThanOrEqual(key, value);
                } else if(hisTaskQuery!=null){
                    hisTaskQuery.processVariableValueGreaterThanOrEqual(key, value);
                } else if(proceQuery!=null){
                    proceQuery.variableValueGreaterThanOrEqual(key, value);
                } else {
                    hisProcessQuery.variableValueGreaterThanOrEqual(key, value);
                }
                break;
            }
            case "LT":{
                if(taskQuery!=null){
                    taskQuery.processVariableValueLessThan(key, value);
                } else if(hisTaskQuery!=null){
                    hisTaskQuery.processVariableValueLessThan(key, value);
                } else if(proceQuery!=null){
                    proceQuery.variableValueLessThan(key, value);
                } else {
                    hisProcessQuery.variableValueLessThan(key, value);
                }
                break;
            }
            case "LTE":{
                if(taskQuery!=null){
                    taskQuery.processVariableValueLessThanOrEqual(key, value);
                } else if(hisTaskQuery!=null){
                    hisTaskQuery.processVariableValueLessThanOrEqual(key, value);
                } else if(proceQuery!=null){
                    proceQuery.variableValueLessThanOrEqual(key, value);
                } else {
                    hisProcessQuery.variableValueLessThanOrEqual(key, value);
                }
                break;
            }
            default:{
                if(taskQuery!=null){
                    taskQuery.processVariableValueEquals(key, value);
                } else if(hisTaskQuery!=null){
                    hisTaskQuery.processVariableValueEquals(key, value);
                } else if(proceQuery!=null){
                    proceQuery.variableValueEquals(key, value);
                } else {
                    hisProcessQuery.variableValueEquals(key, value);
                }
                break;
            }
        }
    }

    public Object execQry(int size, int page){
        if(size>0 && page>0){
            int st=size*(page-1)+1;
            int en=size*page;
            if(taskQuery!=null){
                return taskQuery.listPage(st,en);
            } else if(hisTaskQuery!=null){
                return hisTaskQuery.listPage(st,en);
            } else if(proceQuery!=null){
                return proceQuery.listPage(st,en);
            } else {
                return hisProcessQuery.listPage(st,en);
            }
        } else {
            if(taskQuery!=null){
                return taskQuery.list();
            } else if(hisTaskQuery!=null){
                return hisTaskQuery.list();
            } else if(proceQuery!=null){
                return proceQuery.list();
            } else {
                return hisProcessQuery.list();
            }
        }
    }
}
